# coding=utf-8
import datetime
import logging

from odoo import models, fields, api
from ..controllers import client
from odoo.http import request
from odoo.exceptions import ValidationError, UserError

_logger = logging.getLogger(__name__)


class wx_user(models.Model):
    _name = 'wx.user'
    _description = u'公众号用户'
    _rec_name = 'nickname'
    _order = 'id desc'


    subscribe = fields.Boolean(u'关注状态')
    openid = fields.Char(u'用户标志')
    nickname = fields.Char(u'昵称')
    sex = fields.Selection([('0', '未知'), ('1', u'男'), ('2', u'女')], string=u'性别')
    language = fields.Char(string='语言')
    city = fields.Char(u'城市')
    province = fields.Char(u'省份')
    country = fields.Char(u'国家')
    headimgurl = fields.Char(u'头像')
    subscribe_time = fields.Char(u'关注时间')
    unionid = fields.Char(u'unionid')
    remark = fields.Char("remark")
    group_id = fields.Selection('_get_groups', string=u'所属组', default='0')
    groupid = fields.Integer("groupid")
    tagid_list = fields.Char("tagid_list")
    subscribe_scene = fields.Char("subscribe_scene")
    qr_scene = fields.Integer("qr_scene")
    qr_scene_str = fields.Char("qr_scene_str")
    subscribe_time_show = fields.Datetime(compute='_get_subscribe_time', string=u'关注时间')


    headimg = fields.Html(compute='_get_headimg', string=u'头像')
    last_uuid = fields.Char('会话ID')
    last_uuid_time = fields.Datetime('会话ID时间')

    # 此方法为发送模板消息公用方法
    def wx_send_template_message(self):
        """
        此方法为发送模板工单消息方法
        需要定义data_dic 格式为：
        data_dic: { "first": xxxx, "keyword1": xxxxx, ... "keyword4": xxxxx, "remark":xxxxx}
            first : 列如：亲，您的工单有最新进展， 自己可自定义
            keyword1 工单编号
            keyword2 工单标题
            keyword3 工单状态
            keyword4 工单处理人
            remark : 列如： 我们将向您提供100分的服务，请继续等待。自己可自定义
        openid : 关注者openid
        调用send_template_message(openid data_dic)
        """
        from ..controllers import client
        entry = client.wxenv(self.env)
        if not entry.wx_appid:
            raise ValidationError(u'尚未做公众号对接配置')
        openid = self.openid
        data_dic = {
            "first": '这条消息是工单测试',
            "keyword1": "88888888",
            "keyword2": "销售订单SO8888",
            "keyword3": "订单确认",
            "keyword4": self.env.user.name,
            "remark": "我们将向您提供100分的服务，请继续等待！"
        }
        from werobot.client import ClientException
        try:
            followers_dict = entry.wxclient.send_template_message(openid, data_dic)
        except ClientException as e:
            raise ValidationError(u'微信服务请求异常，异常信息: %s' % e)
        if followers_dict == 0:
            _logger.info(">>>>>>>>>>>>>>>>>>模板消息发送成功<<<<<<<<<<<<<<<<<<<def wx_send_template_message()")
        else:
            _logger.info(">>>>>>>>>>>>>>>>>>模板消息发送失败<<<<<<<<<<<<<<<<<<<def wx_send_template_message()")




    def _parse_values(self, values):
        info = values
        if 'groupid' in info:
            info['group_id'] = str(info['groupid'])
        if 'sex' in info:
            info['sex'] = str(info['sex'])
        if 'tagid_list' in info:
            info['tagid_list'] = str(info['tagid_list'])
        return info


    def write(self, values):
        values = self._parse_values(values)
        objs = super(wx_user, self).write(values)
        return objs

    @api.model
    def create(self, values):
        values = self._parse_values(values)
        obj = super(wx_user, self).create(values)
        return obj

    def update_last_uuid(self, uuid):
        self.write({'last_uuid': uuid, 'last_uuid_time': fields.Datetime.now()})
        self.env['wx.user.uuid'].sudo().create({'openid': self.openid, 'uuid': uuid})

    def get_user_info_all(self, user_list, entry):
        """
        获取列表用户详细信息
        :param user_list: 传过来的用户openen_id 列表
        :param entry: 微信对象
        :return: 返回查询到的列表信息
        {
                   "user_info_list": [
                       {
                           "subscribe": 1,
                           "openid": "otvxTs4dckWG7imySrJd6jSi0CWE",
                           "nickname": "iWithery",
                            ...
                           "subscribe_scene": "ADD_SCENE_QR_CODE",
                           "qr_scene": 98765,
                           "qr_scene_str": ""

                      }, 。。。

        """
        ###批量获取新用户
        # 获取到的用户
        list_new_user = user_list
        # 获取到的用户信息
        user_all_info = []
        len_all = len(list_new_user)
        num = 0
        # 批量拉取，限制100个，需要进行切片，获取到列表，进行切片操作。
        if len_all % 100 == 0:
            num = len_all / 100
        else:
            num = len_all // 100 + 1
        for x in range(1, int(num) + 1):
            if x == 1:
                list_user = list_new_user[x-1:x*100]
                list_all_data = []
                for line in list_user:
                    list_all_data.append({"openid": line})
                    # 这里注意，是否是在package中的方法，新增了get_batch_all_user
                user_info = entry.wxclient.get_batch_all_user(list_all_data)
                user_all_info += user_info['user_info_list']
            else:
                list_user = list_new_user[(x-1)*100: x*100]
                list_all_data = []
                for line in list_user:
                    list_all_data.append({"openid": line})
                user_info = entry.wxclient.get_batch_all_user(list_all_data)
                user_all_info += user_info['user_info_list']
        return user_all_info

    @api.model
    def sync(self):
        """
        全部关注着同步
        :return:
        """
        from ..controllers import client
        entry = client.wxenv(self.env)
        if not entry.wx_appid:
            raise ValidationError(u'尚未做公众号对接配置')
        next_openid = 'init'
        # 全部关注用户列表
        all_user = []
        _logger.info(">>>>>>>>>>>>>>>>>>获取关注用户信息<<<<<<<<<<<<<<<<<<<")
        while next_openid:
            if next_openid == 'init':
                next_openid = None
            from werobot.client import ClientException
            try:
                followers_dict = entry.wxclient.get_followers(next_openid)
            except ClientException as e:
                raise ValidationError(u'微信服务请求异常，异常信息: %s' % e)
            c_total = followers_dict['total']
            m_count = followers_dict['count']
            next_openid = followers_dict['next_openid']
            if next_openid:
                # 拉取全部的关注ID,这里需要注意最大只能拉取1万条
                m_openids = followers_dict['data']['openid']
                all_user = all_user + m_openids
        # 获取本地全部的ID
        local_openids = self.search([]).mapped('openid')
        # 新增用户，找到全部ID中，公众号列表与本地列表对比，如果，公众号用户有，本地没有，说明是新增。
        new_user = [x for x in all_user if x not in local_openids]
        # 删除用户，如果本地列表有，但是公众号列表没有，则说明用户取消关注，删除用户
        delete_user = [x for x in local_openids if x not in all_user]
        # 已有用户，更新操作, 接口和数据库都存在，更新这部分内容
        existing_user = [x for x in all_user if x in local_openids]

        # 创建用户信息
        create_user = self.get_user_info_all(new_user, entry)
        # 更新用户信息
        update_user = self.get_user_info_all(existing_user, entry)

        # 同步一下用户组
        self.env['wx.user.group'].sync()
        # 创建新用户
        len_new = len(create_user)
        _logger.info('共新增%s位关注者' % len_new)
        self.create(create_user)
        # 删除取消关注者
        user_obj = self.env['wx.user']
        for del_user in delete_user:
            user_obj |= self.search([('openid', '=', del_user)])
        user_obj.unlink()
        # 更新现有用户信息
        for user_update in update_user:
            _logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>正在更新用户:" + user_update.get('nickname') or "次用户没有用户名" + "<<<<<<<<<<<<<<<<<<<<<<<<<<<")
            user_info = self.search([('openid', '=', user_update.get('openid'))])
            if user_info.exists():
                user_info.write(user_update)

        _logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>同步更新完成<<<<<<<<<<<<<<<<<<<<<<<<<<<")

    @api.model
    def sync_again(self):
        """
        同步最近关注者
        :return:
        """
        from ..controllers import client
        entry = client.wxenv(self.env)
        if not entry.wx_appid:
            raise ValidationError(u'尚未做公众号对接配置')
        open_id = self.env['wx.user'].search([])
        if len(open_id) > 1:
            next_openid = 'init'
            # 全部关注用户列表
            all_user = []
            _logger.info(">>>>>>>>>>>>>>>>>>获取关注用户信息<<<<<<<<<<<<<<<<<<<")
            while next_openid:
                if next_openid == 'init':
                    next_openid = None
                from werobot.client import ClientException
                try:
                    followers_dict = entry.wxclient.get_followers(next_openid)
                except ClientException as e:
                    raise ValidationError(u'微信服务请求异常，异常信息: %s' % e)
                c_total = followers_dict['total']
                m_count = followers_dict['count']
                next_openid = followers_dict['next_openid']
                if next_openid:
                    # 拉取全部的关注ID,这里需要注意最大只能拉取1万条
                    m_openids = followers_dict['data']['openid']
                    all_user = all_user + m_openids
            # 获取本地全部的ID
            local_openids = self.search([]).mapped('openid')
            # 新增用户，找到全部ID中，公众号列表与本地列表对比，如果，公众号用户有，本地没有，说明是新增。
            new_user = [x for x in all_user if x not in local_openids]
            # 删除用户，如果本地列表有，但是公众号列表没有，则说明用户取消关注，删除用户
            delete_user = [x for x in local_openids if x not in all_user]

            # 创建用户操作
            create_user = self.get_user_info_all(new_user, entry)

            # 同步一下用户组
            self.env['wx.user.group'].sync()
            # 创建新用户
            len_new = len(create_user)
            _logger.info('>>>>>>>>>>>>>>>>>>>>>>>>>>>共新增%s位关注者<<<<<<<<<<<<<<<<<<<<<<<<<<<' % len_new)
            self.create(create_user)
            # 删除取消关注者
            delete_obj = self.env['wx.user']
            for del_user in delete_user:
                _logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>同步删除未关注用户<<<<<<<<<<<<<<<<<<<<<<<<<<<")
                delete_obj |= self.search([('openid', '=', del_user)])
            delete_obj.unlink()
            _logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>同步更新完成<<<<<<<<<<<<<<<<<<<<<<<<<<<")
        else:
            raise ValidationError(u'尚未同步公众号同步者,请先进行同步全部关注者操作')


    def sync_one_wx_user(self):
        """
        单用户同步
        :return:
        """
        from ..controllers import client
        entry = client.wxenv(self.env)
        if not entry.wx_appid:
            raise ValidationError(u'尚未做公众号对接配置')
        openid = self.openid
        g_flag = True
        objs = self.env['wx.user.group'].search([])

        group_list = [e.group_id for e in objs]
        if openid:
            info = entry.wxclient.get_user_info(openid)
            groupid = info.get('groupid')
            if g_flag and groupid and groupid not in group_list:
                self.env['wx.user.group'].sync()
                g_flag = False
            rs = self.search([('openid', '=', openid)])
            _logger.info('正在同步用户,用户的OPENID是： %s .' % (openid))
            if rs.exists():
                rs.write(info)
            else:
                self.create(info)



    @api.model
    def sync_confirm(self):
        """
        同步微信公众号全部用户
        :return:
        """
        new_context = dict(self._context) or {}
        new_context['default_info'] = "此操作可能需要一定时间，确认同步吗？"
        new_context['default_model'] = 'wx.user'
        new_context['default_method'] = 'sync'
        # new_context['record_ids'] = self.id
        return {
            'name': u'确认同步公众号用户',
            'type': 'ir.actions.act_window',
            'res_model': 'wx.confirm',
            'res_id': None,
            'view_mode': 'form',
            'view_type': 'form',
            'context': new_context,
            'view_id': self.env.ref('oejia_wx2.wx_confirm_view_form').id,
            'target': 'new'
        }

    @api.model
    def sync_confirm_new(self):
        """
        同步微信公众号最新关注者
        :return:
        """
        new_context = dict(self._context) or {}
        new_context['default_info'] = "此操作可能需要一定时间，确认同步最新关注者吗？"
        new_context['default_model'] = 'wx.user'
        new_context['default_method'] = 'sync_again'
        new_context['record_ids'] = self.id
        return {
            'name': u'确认同步公众号最新关注用户',
            'type': 'ir.actions.act_window',
            'res_model': 'wx.confirm',
            'res_id': None,
            'view_mode': 'form',
            'view_type': 'form',
            'context': new_context,
            'view_id': self.env.ref('oejia_wx2.wx_confirm_view_form_again').id,
            'target': 'new'
        }


    def _get_headimg(self):
        objs = self
        for self in objs:
            self.headimg = '<img src=%s width="100px" height="100px" />' % (
                        self.headimgurl or '/web/static/src/img/placeholder.png')


    def _get_subscribe_time(self):
        """
        关注时间转换
        :return: 返回时间字符串
        """
        for self_da in self:
            # 这里注意，因为odoo会增加8小时时差，需要我们减去8小时时差的时间戳，返回给odoo的时间。
            dt = datetime.datetime.fromtimestamp(int(self_da.subscribe_time)-(8*60*60))
            self_da.subscribe_time_show = dt.strftime("%Y-%m-%d %H:%M:%S")


    def _get_groups(self):
        Group = self.env['wx.user.group']
        objs = Group.search([])
        return [(str(e.group_id), e.group_name) for e in objs] or [('0', '默认组')]


    def send_text(self, text):
        from werobot.client import ClientException
        from ..controllers import client
        entry = client.wxenv(self.env)
        for obj in self:
            try:
                entry.send_text(obj.openid, text)
            except ClientException as e:
                _logger.info(u'微信消息发送失败 %s' % e)
                raise UserError(u'发送失败 %s' % e)


    def send_text_confirm(self):
        self.ensure_one()
        new_context = dict(self._context) or {}
        new_context['default_model'] = 'wx.user'
        new_context['default_method'] = 'send_text'
        new_context['record_ids'] = self.id
        return {
            'name': u'发送微信消息',
            'type': 'ir.actions.act_window',
            'res_model': 'wx.confirm',
            'res_id': None,
            'view_mode': 'form',
            'view_type': 'form',
            'context': new_context,
            'view_id': self.env.ref('oejia_wx2.wx_confirm_view_form_send').id,
            'target': 'new'
        }


class wx_user_group(models.Model):
    _name = 'wx.user.group'
    _description = u'公众号用户组'
    _rec_name = 'group_name'

    count = fields.Integer(u'用户数', )
    group_id = fields.Integer(u'组编号', )
    group_name = fields.Char(u'组名', )
    user_ids = fields.One2many('wx.user', 'group_id', u'用户', )

    @api.model
    def sync(self):
        from ..controllers import client
        entry = client.wxenv(self.env)
        if not entry.wx_appid:
            raise ValidationError(u'尚未做公众号对接配置')
        from werobot.client import ClientException
        try:
            groups = entry.wxclient.get_groups()
        except ClientException as e:
            raise ValidationError(u'微信服务请求异常，异常信息: %s' % e)
        for group in groups['groups']:
            rs = self.search([('group_id', '=', group['id'])])
            if rs.exists():
                rs.write({
                    'group_name': group['name'],
                    'count': group['count'],
                })
            else:
                self.create({
                    'group_id': str(group['id']),
                    'group_name': group['name'],
                    'count': group['count'],
                })

    @api.model
    def sync_confirm(self):
        """
        同步公众号用户组
        :return:
        """
        new_context = dict(self._context) or {}
        new_context['default_info'] = "此操作可能需要一定时间，确认同步吗？"
        new_context['default_model'] = 'wx.user.group'
        new_context['default_method'] = 'sync'
        # new_context['record_ids'] = self.id
        return {
            'name': u'确认同步公众号用户组',
            'type': 'ir.actions.act_window',
            'res_model': 'wx.confirm',
            'res_id': None,
            'view_mode': 'form',
            'view_type': 'form',
            'context': new_context,
            'view_id': self.env.ref('oejia_wx2.wx_confirm_view_form').id,
            'target': 'new'
        }


class wx_corpuser(models.Model):
    _name = 'wx.corpuser'
    _description = u'企业号用户'

    name = fields.Char('昵称', required=True)
    userid = fields.Char('账号', required=True)
    avatar = fields.Char('头像', )
    position = fields.Char('职位', )
    gender = fields.Selection([('0', '未知'), ('1', '男'), ('2', '女')], string='性别', )
    weixinid = fields.Char('微信号', )
    mobile = fields.Char('手机号', )
    email = fields.Char('邮箱', )
    status = fields.Selection([('1', '已关注'), ('2', '已禁用'), ('4', '未关注'), ('5', '退出企业')], string='状态', default='4')
    extattr = fields.Char('扩展属性', )

    avatarimg = fields.Html(compute='_get_avatarimg', string=u'头像')
    last_uuid = fields.Char('会话ID')
    last_uuid_time = fields.Datetime('会话ID时间')

    # department, enable, english_name, hide_mobile, isleader, order, qr_code, telephone
    alias = fields.Char('别名')

    _sql_constraints = [
        ('userid_key', 'UNIQUE (userid)', '账号已存在 !'),
    ]

    def update_last_uuid(self, uuid):
        self.write({'last_uuid': uuid, 'last_uuid_time': fields.Datetime.now()})
        self.env['wx.corpuser.uuid'].sudo().create({'userid': self.userid, 'uuid': uuid})


    def _get_avatarimg(self):
        objs = self
        for self in objs:
            self.avatarimg = '<img src=%s width="100px" height="100px" />' % (
                        self.avatar or '/web/static/src/img/placeholder.png')

    @api.model
    def create(self, values):
        _logger.info('wx.corpuser create >>> %s' % str(values))
        values['email'] = values['email'] or False
        values['mobile'] = values['mobile'] or False
        if not (values.get('mobile', '') or values.get('email', '')) and not '_from_subscribe' in values:
            raise ValidationError('手机号、邮箱不能同时为空')
        from_subscribe = False
        if '_from_subscribe' in values:
            from_subscribe = True
            values.pop('_from_subscribe')
        obj = super(wx_corpuser, self).create(values)
        if not from_subscribe:
            arg = {}
            for k, v in values.items():
                if v != False and k in ['mobile', 'email', 'weixinid', 'gender']:  # 'alias'
                    arg[k] = v
            arg['department'] = 1
            if 'weixinid' in arg:
                arg['weixin_id'] = arg.pop('weixinid')
            from wechatpy.exceptions import WeChatClientException
            try:
                entry = self.env['wx.corp.config'].corpenv()
                entry.txl_client.user.create(values['userid'], values['name'], **arg)
            except WeChatClientException as e:
                raise ValidationError(u'微信服务请求异常，异常码: %s 异常信息: %s' % (e.errcode, e.errmsg))
        return obj


    def write(self, values):
        _logger.info('wx.corpuser write >>> %s %s' % (str(self), str(values)))
        from_subscribe = False
        if '_from_subscribe' in values:
            from_subscribe = True
            values.pop('_from_subscribe')
        objs = super(wx_corpuser, self).write(values)
        if from_subscribe:
            return objs
        arg = {}
        for k, v in values.items():
            if v != False and k in ['mobile', 'email', 'weixinid', 'gender', 'name']:  # 'alias'
                arg[k] = v
        for obj in self:
            if not (obj.mobile or obj.email):
                raise ValidationError('手机号、邮箱不能同时为空')
            if not arg:
                continue
            from wechatpy.exceptions import WeChatClientException
            try:
                entry = self.env['wx.corp.config'].corpenv()
                entry.txl_client.user.update(obj.userid, **arg)
            except WeChatClientException as e:
                raise ValidationError(u'微信服务请求异常，异常码: %s 异常信息: %s' % (e.errcode, e.errmsg))
        return objs


    def unlink(self):
        _logger.info('wx.corpuser unlink >>> %s' % str(self))
        for obj in self:
            try:
                entry = self.env['wx.corp.config'].corpenv()
                entry.txl_client.user.delete(obj.userid)
            except:
                pass
        ret = super(wx_corpuser, self).unlink()
        return ret

    @api.model
    def sync_from_remote(self, department_id=1):
        '''
        从企业微信通讯录同步
        '''
        from wechatpy.exceptions import WeChatClientException
        try:
            entry = self.env['wx.corp.config'].corpenv()
            config = self.env['wx.corp.config'].sudo().get_cur()
            if not config.Corp_Id:
                raise ValidationError(u'尚未做企业微信对接配置')
            users = entry.txl_client.user.list(department_id, fetch_child=True)
            for info in users:
                info['_from_subscribe'] = True
                info['gender'] = str(info['gender'])
                if 'status' in info:
                    info['status'] = str(info['status'])
                rs = self.search([('userid', '=', info['userid'])])
                if not rs.exists():
                    self.create(info)
                else:
                    rs.write(info)
        except WeChatClientException as e:
            raise ValidationError(u'微信服务请求异常，异常码: %s 异常信息: %s' % (e.errcode, e.errmsg))


    def sync_from_remote_confirm(self):
        """
        企业微信用户到odoo系统
        :return:
        """
        new_context = dict(self._context) or {}
        new_context['default_info'] = "此操作可能需要一定时间，确认同步吗？"
        new_context['default_model'] = 'wx.corpuser'
        new_context['default_method'] = 'sync_from_remote'
        return {
            'name': u'确认同步已有企业微信用户至本系统',
            'type': 'ir.actions.act_window',
            'res_model': 'wx.confirm',
            'res_id': None,
            'view_mode': 'form',
            'view_type': 'form',
            'context': new_context,
            'view_id': self.env.ref('oejia_wx2.wx_confirm_view_form').id,
            'target': 'new'
        }


    def send_text(self, text):
        from wechatpy.exceptions import WeChatClientException
        Param = self.env['ir.config_parameter'].sudo()
        for obj in self:
            try:
                entry = self.env['wx.corp.config'].corpenv()
                entry.client.message.send_text(entry.current_agent, obj.userid, text)
            except WeChatClientException as e:
                _logger.info(u'微信消息发送失败 %s' % e)
                raise UserError(u'发送失败 %s' % e)


    def send_text_confirm(self):
        self.ensure_one()

        new_context = dict(self._context) or {}
        new_context['default_model'] = 'wx.corpuser'
        new_context['default_method'] = 'send_text'
        new_context['record_ids'] = self.id
        return {
            'name': u'发送微信消息',
            'type': 'ir.actions.act_window',
            'res_model': 'wx.confirm',
            'res_id': None,
            'view_mode': 'form',
            'view_type': 'form',
            'context': new_context,
            'view_id': self.env.ref('oejia_wx2.wx_confirm_view_form_send').id,
            'target': 'new'
        }
